package com.boarsoft.boar.redis;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy;

import com.boarsoft.agent.AgentService;
import com.boarsoft.bean.ReplyInfo;
import com.boarsoft.cache.redis.RedisNodeAgent;
import com.boarsoft.common.util.StreamUtil;
import com.boarsoft.rpc.core.RpcContext;

import redis.clients.jedis.Jedis;

public class RedisNodeAgentImpl implements RedisNodeAgent {
	private static final Logger log = LoggerFactory.getLogger(RedisNodeAgentImpl.class);

	protected String path = "~/shells/redis";
	protected int port = 9925;

	@Lazy
	@Autowired
	@Qualifier("agentX")
	protected AgentService agentX;

	public ReplyInfo<Object> batch(File file, String ip, int port, String to, String code) {
		String cmd = String.format("sh %s/%s.sh %s %d", path, code, ip, port);
		try {
			this.copy2(file, to, ip, port);
			return this.executeShell(ip, cmd);
		} catch (Throwable e) {
			return new ReplyInfo<Object>(e.getMessage());
		}
	}

	protected void copy2(File from, String to, String ip, int port) throws Throwable {
		log.info("Copy file {} to {}/{}", from, ip, to);
		BufferedInputStream bis = null;
		String addr = new StringBuilder().append(ip).append(":").append(port).toString();
		RpcContext.specify2(addr); // 指定服务器
		try {
			bis = new BufferedInputStream(new FileInputStream(from));
			byte[] buf = new byte[40960];
			int len = 0;
			for (int i = 0; (len = bis.read(buf)) > 0; i++) {
				agentX.write2(i, to, buf, 0, len);
			}
		} finally {
			StreamUtil.close(bis);
			RpcContext.specify2(null);
		}
	}

	protected ReplyInfo<Object> executeShell(String ip, String cmd) {
		RpcContext.specify2(String.format("%s:%d", ip, port));
		try {
			return agentX.executeShell(cmd);
		} catch (Exception e) {
			return new ReplyInfo<Object>(e.getMessage());
		} finally {
			RpcContext.specify2(null);
		}
	}

	@Override
	public ReplyInfo<Object> startup(String ip, int port) {
		log.info("Startup redis node {}:{} as master", ip, port);
		String cmd = String.format("sh %s/startMaster.sh %s %d", path, ip, port);
		log.debug("Execute shell command {}", cmd);
		return this.executeShell(ip, cmd);
	}

	@Override
	public ReplyInfo<Object> startup(String ip, int port, String master) {
		log.info("Startup redis node {}:{} as slave of {}", ip, port, master);
		String[] a = master.split(":");
		String cmd = String.format("sh %s/startSlave.sh %s %d %s %s", path, ip, port, a[0], a[1]);
		log.debug("Execute shell command {}", cmd);
		return this.executeShell(ip, cmd);
	}

	@Override
	public ReplyInfo<Object> shutdown(String ip, int port) {
		log.info("Shutdown redis node {}:{}", ip, port);
		String cmd = String.format("sh %s/stop.sh %s %d", path, ip, port);
		log.debug("Execute shell command {}", cmd);
		return this.executeShell(ip, cmd);
	}

	@Override
	public ReplyInfo<Object> toMaster(String ip, int port) {
		log.info("Switch redis node {}:{} to master", ip, port);
		String cmd = String.format("sh %s/toSlave.sh %s %d %s %s", path, ip, port, "NO", "ONE");
		log.debug("Execute shell command {}", cmd);
		return this.executeShell(ip, cmd);
	}

	@Override
	public ReplyInfo<Object> toSlave(String ip, int port, String master) {
		log.info("Switch redis node {}:{} to slave of {}", ip, port, master);
		String[] a = master.split(":");
		String cmd = String.format("sh %s/toSlave.sh %s %d %s %s", path, ip, port, a[0], a[1]);
		log.debug("Execute shell command {}", cmd);
		return this.executeShell(ip, cmd);
	}

	@Override
	public ReplyInfo<Object> getInfo(String host, int port) {
		Jedis jedis = null;
		try {
			jedis = new Jedis(host, port);
			return new ReplyInfo<Object>(true, jedis.info());
		} finally {
			StreamUtil.close(jedis);
		}
		// log.info("Get info of redis node {}:{}", host, port);
		// String cmd = String.format("sh %s/info.sh %s %d", path, host, port);
		// log.debug("Execute shell command {}", cmd);
		// return this.executeShell(host, cmd);
	}

	@Override
	public ReplyInfo<Object> exec(String host, int port, String rc) {
		log.info("Ask redis node {}:{} execute command: [{}]", host, port, rc);
		String cmd = String.format("sh %s/exec.sh %s %d \"%s\"", path, host, port, rc);
		log.debug("Execute shell command {}", cmd);
		return this.executeShell(host, cmd);
	}

	public String getPath() {
		return path;
	}

	public void setPath(String path) {
		this.path = path;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}
}
